/*
 * TimerDelegate.cpp  0.4.0 / Dec 04, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "TimerDelegate.h"

#include "SwingDelegate.h"
#include "SwingUtilitiesDelegate.h"

// TimerDelegate :: Protected Constructor. -------------------------------------

/*!
 * \brief Constructs new TimerDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param obj the Timer java object
 * \param delay the number of milliseconds between timer events
 * \param initialDelay the initial delay
 * \param singleShot \c true if the timer is single-shot timer
 */
TimerDelegate::TimerDelegate(JNIEnv *env, jobject obj, jint delay,
                             jint initialDelay, jboolean singleShot)
  : m_objref(JNIWrapper::newWeakGlobalRef(env, obj)), m_timer(0)
{
  m_timer.setInterval(delay);
  m_timer.setSingleShot(singleShot);
  if (m_objref) { // check for OutOfMemoryError
    connect(&m_timer, SIGNAL(timeout()), this, SLOT(timeout()));
    m_timer.start(initialDelay);
  }
}

// TimerDelegate :: Protected Destructor. --------------------------------------

/*!
 * \brief Destroys the TimerDelegate object.
 */
TimerDelegate::~TimerDelegate()
{
  if (m_objref) {
    JNISwingWrapper::deleteWeakGlobalRef(m_objref);
  }
}

// TimerDelegate :: Native Calls. ----------------------------------------------

/*!
 * \brief Destroys the delegate object.
 *
 * \param env the JNIEnv pointer
 */
void TimerDelegate::destroy(JNIEnv *env)
{
  Q_UNUSED(env);
  if (SwingDelegate::isDisposed()) {
    delete this; // OK - referenced only from java
  } else {
    deleteLater();
  }
}

/*!
 * \brief Sets timer interval.
 *
 * \param env the JNIEnv pointer
 * \param interval the timer interval
 */
void TimerDelegate::setInterval(JNIEnv *env, jint interval)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setInterval, SWING_ENV_ARG, JINT_ARG(interval))
  m_timer.setInterval(interval);
}

/*!
 * \brief Sets whether or not the timer is single shot-timer.
 *
 * \param env the JNIEnv pointer
 * \param singleShot if \c true the timer is single shot-timer
 */
void TimerDelegate::setSingleShot(JNIEnv *env, jboolean singleShot)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setSingleShot, SWING_ENV_ARG, JBOOLEAN_ARG(singleShot))
  m_timer.setSingleShot(singleShot);
}

// TimerDelegate :: Static Native Calls. ---------------------------------------

/*!
 * \brief Initializes TimerDelegate class.
 *
 * \param env the JNIEnv pointer
 * \param cls the Timer java class
 *
 * \exception FatalError if failed
 */
void TimerDelegate::initialize(JNIEnv *env, jclass cls)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(!sm_createMID);
  if (!INIT_UMID(create, cls, "(IIZ)J") || !INIT_UMID(timeout, cls, "()V")) {
    FATAL_LOGGED_ERROR("TimerDelegate initialization failed");
  }
}

/*!
 * \brief Returns new instance of the delegate object.
 *
 * \param env the JNIEnv pointer
 * \param obj the Timer java object
 * \param delay the number of milliseconds between timer events
 * \param initialDelay the initial delay
 * \param singleShot \c true if the timer is single-shot timer
 *
 * \return new instance of the delegate object.
 */
jlong TimerDelegate::newInstance(JNIEnv *env, jobject obj, jint delay,
                                 jint initialDelay, jboolean singleShot)
{
  if (JNISwingWrapper::isSwingThread(env)) {
    return reinterpret_cast<jlong>(new TimerDelegate(env, obj, delay,
                                                     initialDelay, singleShot));
  }
  return SwingUtilitiesDelegate::invokeLongAndWait(env, obj, sm_createMID, delay,
                                                   initialDelay, singleShot);
}

// TimerDelegate :: Native Callback. -------------------------------------------

/*!
 * \brief Calls timeout method of the Timer java object.
 */
void TimerDelegate::timeout()
{
  if (SwingDelegate::isDisposed()) {
    m_timer.stop();
    delete this;
  } else {
    JNISwingWrapper::callVoidMethod(m_objref, sm_timeoutMID);
  }
}

// TimerDelegate :: Private Static Data Members. -------------------------------

jmethodID TimerDelegate::sm_createMID = 0;
jmethodID TimerDelegate::sm_timeoutMID = 0;
